#include "RequestNotifier.h"

#include <qbkernel/include/qb_base.h>

#include "MessagePoster.h"

RequestNotifier& RequestNotifier::instance() {
  static RequestNotifier s_rn;
  return s_rn;
}

void RequestNotifier::registReqReceiver(int req, MessageReceiver* pr) {
  qb::base::ScopedLock<qb::base::Spinlock> locker(m_lock);
  m_receivers[req] = pr;
}

void RequestNotifier::unRegistReqReceiver(int req, const MessageReceiver* pr) {
  qb::base::ScopedLock<qb::base::Spinlock> delLocker(m_delLock);
  qb::base::ScopedLock<qb::base::Spinlock> locker(m_lock);
  auto iter = m_receivers.find(req);
  if (iter != m_receivers.end()) m_receivers.erase(iter);
}

void RequestNotifier::registPushReceiver(const PushMsgInfo& pmi,
                                         MessageReceiver* pr) {
  qb::base::ScopedLock<qb::base::Spinlock> locker(m_pushLock);
  m_pushReceivers.insert({pmi, pr});
  if (pmi.extractFuncPtr != nullptr)
    m_paramExtractors[pmi.funcId] = pmi.extractFuncPtr;
}

void RequestNotifier::unRegistPushReceiver(const PushMsgInfo& pmi,
                                           const MessageReceiver* pr) {
  qb::base::ScopedLock<qb::base::Spinlock> delLocker(m_pushDelLock);
  qb::base::ScopedLock<qb::base::Spinlock> locker(m_pushLock);
  auto receivers = m_pushReceivers.equal_range(pmi);
  for (auto iter = receivers.first; iter != receivers.second;) {
    if (iter->second == pr)
      iter = m_pushReceivers.erase(iter);
    else
      ++iter;
  }
}

void RequestNotifier::OnResponse(THIS_ int32_t funcId,
                                 const qb::SSAckMsg& msg) {
  {
    qb::base::ScopedLock<qb::base::Spinlock> lockerDel(m_pushDelLock);

    {
      qb::base::ScopedLock<qb::base::Spinlock> locker(m_pushLock);
      m_pushReceiversCopy = m_pushReceivers;
    }

    auto receivers = m_pushReceiversCopy.equal_range({funcId, "", nullptr});
    for (auto iter = receivers.first; iter != receivers.second; ++iter) {
      iter->second->onDataArrived(msg);
    }

    auto extractor = m_paramExtractors.find(funcId);
    if (extractor != m_paramExtractors.end() && extractor->second) {
      NotifyFunc func = std::bind(&RequestNotifier::notifyPushReceiver, this,
                                  std::placeholders::_1, std::placeholders::_2);
      extractor->second(msg, func);
    }
  }

  int req = msg.m_RequestID;
  if (req > 0) {
    qb::base::ScopedLock<qb::base::Spinlock> delLocker(m_delLock);
    std::map<int, MessageReceiver*> receiversCopy;
    {
      qb::base::ScopedLock<qb::base::Spinlock> locker(m_lock);
      receiversCopy = m_receivers;
    }

    auto iter = receiversCopy.find(req);
    if (iter != receiversCopy.end()) iter->second->onDataArrived(msg);
  }
}

void RequestNotifier::notifyPushReceiver(const PushMsgInfo& pmi,
                                         const qb::SSAckMsg& msg) {
  auto iter = m_pushReceiversCopy.find(pmi);
  if (iter != m_pushReceiversCopy.end()) iter->second->onDataArrived(msg);
}

bool PushMsgInfo::operator<(const PushMsgInfo& other) const {
  if (funcId < other.funcId) return true;
  if (funcId == other.funcId) return paramter < other.paramter;

  return false;
}

bool PushMsgInfo::operator==(const PushMsgInfo& other) const {
  if (funcId == other.funcId && paramter == other.paramter) return true;

  return false;
}

void registSpecificMsgProcessor() {
  static bool s_done = false;
  if (s_done) return;

  qb::qbBase::getMessageBond()->SetSpecificMsgProcessor(
      &RequestNotifier::instance());
}

void unRegistSpecificMsgProcessor() {
  qb::qbBase::getMessageBond()->SetSpecificMsgProcessor(nullptr);
}
